package com.nexus.core.query;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.nexus.core.query.annotation.QueryCondition;
import com.nexus.core.query.annotation.QuerySort;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 自动查询构造器
 *
 * @Date 2025/7/24 17:23
 * @Author luzhengning
 **/
public class QueryWrapperBuilder<T, DTO> {
    private final QueryWrapper<T> queryWrapper;
    private final Map<String, Object> paramMap;

    public QueryWrapperBuilder() {
        this.queryWrapper = new QueryWrapper<>();
        this.paramMap = new HashMap<>();
    }

    /**
     * 根据参数对象构建QueryWrapper
     */
    public QueryWrapperBuilder<T, DTO> build(Object paramObj) {
        if (paramObj == null) return this;

        Class<?> clazz = paramObj.getClass();
        Field[] fields = clazz.getDeclaredFields();

        // 处理排序字段（优先处理）
        processOrderFields(paramObj, fields);

        // 处理查询条件字段
        for (Field field : fields) {
            processQueryField(paramObj, field);
        }
        return this;
    }

    /**
     * 获取构建完成的QueryWrapper
     */
    public QueryWrapper<T> getQueryWrapper() {
        return queryWrapper;
    }

    /**
     * 获取参数Map（用于XML配置的SQL）
     */
    public Map<String, Object> getParamMap() {
        return paramMap;
    }

    private void processQueryField(Object paramObj, Field field) {
        QueryCondition condition = field.getAnnotation(QueryCondition.class);
        if (condition == null) return;

        try {
            field.setAccessible(true);
            // 字段值
            Object value = field.get(paramObj);
            // 处理空值&&是否忽略空值
            if (value == null && condition.ignoreNull()) return;
            // 字符串值处理
            value = processString(value);
            // 查询字段名
            String fieldName = getFieldName(field, condition);

            // 处理不同类型的查询
            switch (condition.type()) {
                case EQ:
                    queryWrapper.eq(fieldName, value);
                    break;
                case NE:
                    queryWrapper.ne(fieldName, value);
                    break;
                case LIKE:
                    queryWrapper.like(fieldName, value);
                    break;
                case LIKE_LEFT:
                    queryWrapper.likeLeft(fieldName, value);
                    break;
                case LIKE_RIGHT:
                    queryWrapper.likeRight(fieldName, value);
                    break;
                case GT:
                    queryWrapper.gt(fieldName, value);
                    break;
                case LT:
                    queryWrapper.lt(fieldName, value);
                    break;
                case GE:
                    queryWrapper.ge(fieldName, value);
                    break;
                case LE:
                    queryWrapper.le(fieldName, value);
                    break;
                case BETWEEN:
                    handleBetween(condition, fieldName, value);
                    break;
                case IN:
                    handleIn(condition, fieldName, value, false);
                    break;
                case NOT_IN:
                    handleIn(condition, fieldName, value, true);
                    break;
                case IS_NULL:
                    queryWrapper.isNull(fieldName);
                    break;
                case IS_NOT_NULL:
                    queryWrapper.isNotNull(fieldName);
                    break;
            }

            // 添加到参数Map
            if (value != null) {
                paramMap.put(fieldName, value);
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to access field: " + field.getName(), e);
        }
    }

    /**
     * 字符串值处理
     *
     * @Date 2025/7/25 9:35
     * @Author luzhengning
     **/
    private Object processString(Object value) {
        // 检查value是否为String类型
        if (value instanceof String strValue) {
            // 如果是String类型，则去除头和尾的空格
            strValue = strValue.trim(); // 去除前后的空格和换行符（如果有的话）
            strValue = strValue.replaceAll("\\r?\\n", ""); //  去除所有的换行符（\r\n或\n）
            value = strValue; // 将处理后的字符串重新赋值给valu
        }
        return value;
    }

    private void processOrderFields(Object paramObj, Field[] fields) {
        List<OrderField> orderFields = new ArrayList<>();

        for (Field field : fields) {
            QueryCondition order = field.getAnnotation(QueryCondition.class);
            if (order == null || order.order() == QuerySort.CUSTOM) {
                continue;
            }
            if (order == null) continue;

            try {
                field.setAccessible(true);
                Object value = field.get(paramObj);

                // 排序字段不需要值，只需要注解
                if (value != null) continue;

                String fieldName = getFieldName(field, null);
                orderFields.add(new OrderField(fieldName, order.order(), order.priority()));
            } catch (IllegalAccessException e) {
                // 忽略无法访问的字段
            }
        }

        // 按优先级排序
        orderFields.sort(Comparator.comparingInt(OrderField::getPriority));

        // 应用排序
        for (OrderField orderField : orderFields) {
            if (orderField.getOrder() == QuerySort.ASC) {
                queryWrapper.orderByAsc(orderField.getFieldName());
            } else {
                queryWrapper.orderByDesc(orderField.getFieldName());
            }
        }
    }

    /**
     * 获取查询字段
     *
     * @Date 2025/7/25 9:26
     * @Author luzhengning
     **/
    private String getFieldName(Field field, QueryCondition condition) {
        if (condition != null && !condition.tableField().isEmpty()) {
            return condition.tableField();
        }
        // 驼峰转下划线
        return StringUtils.camelToUnderline(field.getName());
    }
    /**
     * 区间查询
     * @Date 2025/7/25 10:20
     * @Author luzhengning
     **/
    private void handleBetween(QueryCondition condition, String fieldName, Object value) {
        if (value == null) return;

        String[] values;
        if (value instanceof String) {
            values = ((String) value).split(condition.rangeSeparator());
        } else if (value instanceof Collection<?> collection) {
            values = collection.stream().map(Object::toString).toArray(String[]::new);
        } else {
            throw new IllegalArgumentException("BETWEEN requires String or Collection");
        }

        if (values.length != 2) {
            throw new IllegalArgumentException("BETWEEN requires exactly two values");
        }

        queryWrapper.between(fieldName, values[0], values[1]);
    }
    /**
     * IN查询
     * @Date 2025/7/25 10:20
     * @Author luzhengning
     **/
    private void handleIn(QueryCondition condition, String fieldName, Object value, boolean notIn) {
        if (value == null) return;

        Collection<?> values;
        if (value instanceof String) {
            values = Arrays.asList(((String) value).split(condition.inSeparator()));
        } else if (value instanceof Collection) {
            values = (Collection<?>) value;
        } else if (value.getClass().isArray()) {
            values = Arrays.asList((Object[]) value);
        } else {
            throw new IllegalArgumentException("IN requires String, Collection or Array");
        }

        if (values.isEmpty()) return;

        if (notIn) {
            queryWrapper.notIn(fieldName, values);
        } else {
            queryWrapper.in(fieldName, values);
        }
    }

    private static class OrderField {
        private final String fieldName;
        private final QuerySort order;
        private final int priority;

        public OrderField(String fieldName, QuerySort order, int priority) {
            this.fieldName = fieldName;
            this.order = order;
            this.priority = priority;
        }

        public String getFieldName() {
            return fieldName;
        }

        public QuerySort getOrder() {
            return order;
        }

        public int getPriority() {
            return priority;
        }
    }

    /**
     * 字符串工具类
     */
    private static class StringUtils {
        public static String camelToUnderline(String str) {
            if (str == null || str.isEmpty()) {
                return str;
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                if (Character.isUpperCase(c)) {
                    if (i > 0) {
                        sb.append('_');
                    }
                    sb.append(Character.toLowerCase(c));
                } else {
                    sb.append(c);
                }
            }
            return sb.toString();
        }
    }
}
